package com.example.socket.utils;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * MAP 转换相关的工具类 注意,Map的Key只能为简单类型 ,不可采用复杂类型.
 */
@SuppressWarnings("unchecked")
public final class JsonUtils {

    public static final TypeFactory TYPE_FACTORY = TypeFactory.defaultInstance();

    public static final ObjectMapper MAPPER;

    static {
        MAPPER = new ObjectMapper();
        MAPPER.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        MAPPER.enable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
        MAPPER.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        MAPPER.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
        MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        // Long 类型数据映射为字符串
        SimpleModule module = new SimpleModule();
        JsonSerializer<Long> longSerializer = new JsonSerializer<Long>() {
            @Override
            public void serialize(Long value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                    JsonProcessingException {
                jgen.writeString(String.valueOf(value));
            }

        };
        JsonDeserializer<? extends Long> longDeserializer = new JsonDeserializer<Long>() {
            @Override
            public Long deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
                    JsonProcessingException {
                return Long.valueOf(jp.getValueAsString());
            }
        };
        JsonSerializer<BigInteger> bigIntSerializer = new JsonSerializer<BigInteger>() {
            @Override
            public void serialize(BigInteger value, JsonGenerator jgen, SerializerProvider provider)
                    throws IOException, JsonProcessingException {

                jgen.writeString(String.valueOf(value));
            }
        };
        JsonSerializer<BigDecimal> bigDecSerializer = new JsonSerializer<BigDecimal>() {
            @Override
            public void serialize(BigDecimal value, JsonGenerator jgen, SerializerProvider provider)
                    throws IOException, JsonProcessingException {
                jgen.writeString(String.valueOf(value));
            }
        };
        // BITSET
        JsonSerializer<BitSet> bitsetSerializer = new JsonSerializer<BitSet>() {
            @Override
            public void serialize(BitSet value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                    JsonProcessingException {
                jgen.writeString(byte2hex(value.toByteArray()));
            }
        };
        JsonDeserializer<? extends BitSet> bitsetDeserializer = new JsonDeserializer<BitSet>() {
            @Override
            public BitSet deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
                    JsonProcessingException {
                return BitSet.valueOf(hex2byte(jp.getValueAsString().getBytes()));
            }
        };

        module.addSerializer(long.class, longSerializer);
        module.addSerializer(Long.class, longSerializer);
        module.addSerializer(BigInteger.class, bigIntSerializer);
        module.addSerializer(BigDecimal.class, bigDecSerializer);
        module.addSerializer(BitSet.class, bitsetSerializer);

        module.addDeserializer(long.class, longDeserializer);
        module.addDeserializer(Long.class, longDeserializer);
        module.addDeserializer(BitSet.class, bitsetDeserializer);

        MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        MAPPER.registerModule(module);
    }

    private JsonUtils() {
        throw new IllegalAccessError("该类不允许实例化");
    }

    /**
     * 将对象转换为 MAP 的字符串格式
     * @param obj 被转换的对象
     * @return 当参数为空时会返回null
     */
    public static String object2String(Object obj) {
        if (obj == null) {
            return null;
        }
        StringWriter writer = new StringWriter();
        try {
            MAPPER.writeValue(writer, obj);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.format("将对象[{}]转换为JSON字符串时发生异常", obj, e);
            throw new RuntimeException(message.getMessage(), e);
        }
        return writer.toString();
    }

    /**
     * 将 MAP 格式的字符串转换为 map
     * @param json MAP，允许为空
     * @return json为null时会返回空的Map实例
     */
    public static Map<String, Object> string2Map(String json) {
        try {
            if (StringUtils.isBlank(json)) {
                return HashMap.class.newInstance();
            }
            JavaType type = TYPE_FACTORY.constructMapType(HashMap.class, String.class, Object.class);
            return MAPPER.readValue(json, type);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", json);
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    /**
     * 将 MAP 格式的字符串转换为数组
     * @param <T>
     * @param json 字符串
     * @param clz 数组类型
     * @return json为null时会返回null
     */
    public static <T> T[] string2Array(String json, Class<T> clz) {
        try {
            if (StringUtils.isBlank(json)) {
                return null;
            }
            JavaType type = TYPE_FACTORY.constructArrayType(clz);
            return (T[]) MAPPER.readValue(json, type);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为数组时出现异常", json, e);
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    /**
     * 将 MAP 格式的字符串转换为对象
     * @param <T>
     * @param json 字符串
     * @param clz 对象类型
     * @return json为null时会返回null
     */
    public static <T> T string2Object(String json, Class<T> clz) {
        try {
            if (StringUtils.isBlank(json)) {
                return null;
            }
            JavaType type = TYPE_FACTORY.constructType(clz);
            return (T) MAPPER.readValue(json, type);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.arrayFormat("将字符串[{}]转换为对象[{}]时出现异常",
                    new Object[]{json, clz.getSimpleName(), e});
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    /***
     * json 泛型转换
     * @param tr 示例 new TypeReference<List<Long>>(){}
     **/
    public static <T> T string2GenericObject(String json, TypeReference<T> tr) {
        if (StringUtils.isBlank(json)) {
            return null;
        } else {
            try {
                return (T) MAPPER.readValue(json, tr);
            } catch (Exception e) {
                FormattingTuple message = MessageFormatter.arrayFormat("将字符串[{}]转换为[{}]时出现异常", new Object[]{json, tr});
                throw new RuntimeException(message.getMessage(), e);
            }
        }
    }

    /***
     * json数组泛型转换
     * @param tr 示例 new TypeReference<List<Long>>(){}
     **/
    public static <T> T bytes2GenericObject(byte[] json, TypeReference<T> tr) {
        if (json == null || json.length == 0) {
            return null;
        } else {
            try {
                return (T) MAPPER.readValue(json, tr);
            } catch (Exception e) {
                FormattingTuple message = MessageFormatter.arrayFormat("将字符串[{}]转换为[{}]时出现异常", new Object[]{json, tr});
                throw new RuntimeException(message.getMessage(), e);
            }
        }
    }

    @SuppressWarnings("rawtypes")
    public static <T> T map2Object(Map map, TypeReference<T> tr) {
        if (map == null) {
            return null;
        } else {
            try {

                return (T) MAPPER.convertValue(map, tr);
            } catch (Exception e) {
                FormattingTuple message = MessageFormatter.arrayFormat("将map[{}]转换为[{}]时出现异常", new Object[]{map, tr});
                throw new RuntimeException(message.getMessage(), e);
            }
        }
    }

    /**
     * 将 MAP 格式的字符串转换为集合
     * @param <T>
     * @param json 字符串
     * @param collectionType 集合类型
     * @param elementType 元素类型
     * @return json为null时会返回空的集合实例
     */
    public static <C extends Collection<E>, E> C string2Collection(String json, Class<C> collectionType,
                                                                   Class<E> elementType) {
        try {
            if (StringUtils.isBlank(json)) {
                return collectionType.newInstance();
            }
            JavaType type = TYPE_FACTORY.constructCollectionType(collectionType, elementType);
            return MAPPER.readValue(json, type);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.arrayFormat("将字符串[{}]转换为集合[{}]时出现异常", new Object[]{json, collectionType.getSimpleName()});
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    /**
     * 将字符串转换为{@link HashMap}对象实例
     * @param json 被转换的字符串
     * @param keyType 键类型
     * @param valueType 值类型
     * @return json为null时会返回空的HashMap实例
     */
    public static <K, V> Map<K, V> string2Map(String json, Class<K> keyType, Class<V> valueType) {
        try {
            if (StringUtils.isBlank(json)) {
                return HashMap.class.newInstance();
            }
            JavaType type = TYPE_FACTORY.constructMapType(HashMap.class, keyType, valueType);
            return (Map<K, V>) MAPPER.readValue(json, type);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", json);
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    /**
     * 将字符串转换为特定的{@link Map}对象实例
     * @param json 被转换的字符串
     * @param keyType 键类型
     * @param valueType 值类型
     * @param mapType 指定的{@link Map}类型
     * @return json为空时会返回空的Map实例
     */
    public static <M extends Map<K, V>, K, V> M string2Map(String json, Class<K> keyType, Class<V> valueType,
                                                           Class<M> mapType) {
        try {
            if (StringUtils.isBlank(json)) {
                return mapType.newInstance();
            }
            JavaType type = TYPE_FACTORY.constructMapType(mapType, keyType, valueType);
            return MAPPER.readValue(json, type);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", json);
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    public static Object string2Object(String json, Type type) {
        try {
            if (StringUtils.isBlank(json)) {
                return null;
            }
            JavaType javaType = TYPE_FACTORY.constructType(type);
            return MAPPER.readValue(json, javaType);
        } catch (Exception e) {
            FormattingTuple message = MessageFormatter.arrayFormat("将字符串[{}]转换为[{}]时出现异常", new Object[]{json, type.getClass().getSimpleName(), e});
            throw new RuntimeException(message.getMessage(), e);
        }
    }

    public static JsonNode readTree(String json) throws IOException {
        return MAPPER.readTree(json);
    }

    /**
     * 二行制转字符串
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        StringBuilder sb = new StringBuilder();
        String stmp = "";
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                sb.append("0").append(stmp);
            } else {
                sb.append(stmp);
            }
        }
        return sb.toString().toUpperCase();
    }

    public static byte[] hex2byte(byte[] b) {
        if ((b.length % 2) != 0) {
            throw new IllegalArgumentException("长度[" + b.length + "]不是偶数");
        }
        byte[] b2 = new byte[b.length / 2];
        for (int n = 0; n < b.length; n += 2) {
            String item = new String(b, n, 2);
            b2[n / 2] = (byte) Integer.parseInt(item, 16);
        }
        return b2;
    }

    public static void main(String[] args) {
        String ss = "{playerId:\"11588737\",roomNumber:\"0\",token:\"ab6976b1ab6c6e4b382cd262951cee06\",P:\"D7CE9116AF18214978C09622F302769B04\",platformId:\"10001\",sign:\"SL4vc0FE/TkIHxMkjYzWVNxsB3We/hcYpAAZVmoIrxsLUICSRvrU1JkEzkmDo5YPLUnemH4AL4DZ0Pu+T1mCPkb5XR3sFEAF3DMUD5uBj5c4wvDXDkUeBs+pCR82QKGarPuELPb3ECODXqv2/FnGTtj7lAi0g3PJhGKIm29D24U=\"}";
        Map<String, Object> bd = JsonUtils.string2Map(ss);
        System.out.println(bd);
    }
}